﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using Opennav.MapGenerator.Map.Roads;
using System.IO;
using Opennav.MapGenerator.Map.MapTiles;
using Opennav.MapGenerator.Geometry;

namespace Opennav.MapGenerator.Map.Roads
{
    /// <summary>
    /// 
    /// </summary>
    public class RoadSegment
    {
        private int _offset = -1;
        private List<MapLine> _mapLines = new List<MapLine>();

        public static ushort LAST_MAPLINE = 0x8000;

        public static byte LAST_SEGMENT_FLAG = 0x80;
        public static byte ONEWAY_FLAG = 0x40;
        public static byte BACKWARD_FLAG = 0x20;
        public static byte TOLL_FLAG = 0x10;

        public RoadSegment()
        {
            this.Last = false;
        }

        public int Offset
        {
            get
            {
                Debug.Assert(_offset >= 0);
                return _offset;
            }
            set
            {
                _offset = value;
            }
        }

        public Road Road { get; set; }

        public RoadJunction From { get; set; }

        public RoadJunction To { get; set; }

        public RoadType Type { get; set; }

        public bool OneWay { get; set; }

        public bool Toll { get; set; }

        public bool Last { get; set; }

        public bool Backward { get; set; }

        public byte MaxSpeed { get; set; }

        public ushort Length { get; set; }

        public IList<MapLine> MapLines { get { return _mapLines; } }

        public void Optimize()
        {
            if (MapLines.Count == 1) return;
            List<Coordinate> coordinates = new List<Coordinate>();
            for (int i = 0; i < MapLines.Count; i++) 
            {
                coordinates.AddRange(MapLines[i].Coordinates);
                if (i != MapLines.Count - 1)
                    coordinates.RemoveAt(coordinates.Count - 1);
            }
            MapLine full = new MapLine(MapLines[0].Type, coordinates.ToArray(), this, MapLines[0].MinResolution, MapLines[0].MaxResolution);
            MapLines.Clear();
            MapLines.Add(full);
        }

        public void Write1(Stream stream)
        {
            BinaryWriter writer = new BinaryWriter(stream);

            byte type = (byte)Type;
            if (Last) type = (byte)(type | LAST_SEGMENT_FLAG);
            if (OneWay) type = (byte)(type | ONEWAY_FLAG);
            if (Backward) type = (byte)(type | BACKWARD_FLAG);
            if (Toll) type = (byte)(type | TOLL_FLAG);
            writer.Write(type);

            int roadId = Road.Id;
            writer.Write((byte)(roadId & 0xff));
            writer.Write((ushort)(roadId >> 8));

            writer.Write((int)0);
            writer.Write((int)0);

            writer.Write(MaxSpeed);

            writer.Write(Length);

            Debug.Assert(_mapLines.Count > 0);
            for (int i = 0; i < _mapLines.Count; i++)
            {
                MapReference reference = _mapLines[i].References.Last();
                ushort objectId = (ushort)reference.ObjectId;
                if (i == _mapLines.Count - 1)
                    objectId = (ushort)(objectId | LAST_MAPLINE);
                writer.Write(objectId);
                writer.Write(reference.TileId);
            }
        }

        public void Write2(Stream stream)
        {
            BinaryWriter writer = new BinaryWriter(stream);
            writer.Seek(4, SeekOrigin.Current);
            writer.Write(From.Offset);
            writer.Write(To.Offset);
        }
    }
}
